/**
 * @file raft.h
 * @brief Raft 共识算法核心类定义
 * 
 * 实现了 Raft 分布式共识算法的核心功能
 * 包括领导者选举、日志复制、快照机制等
 * 提供分布式系统的强一致性保证
 */
#ifndef RAFT_H
#define RAFT_H

#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include "ApplyMsg.h"
#include "Persister.h"
#include "boost/any.hpp"
#include "boost/serialization/serialization.hpp"
#include "config.h"
#include "monsoon.h"
#include "raftRpcUtil.h"
#include "util.h"

// ========== 网络状态常量 ==========
/// @brief 网络状态表示 todo：可以在rpc中删除该字段，实际生产中是用不到的.
constexpr int Disconnected = 0;  ///< 网络断开状态，用于调试网络分区
constexpr int AppNormal = 1;     ///< 网络正常状态

// ========== 投票状态常量 ==========
constexpr int Killed = 0;   ///< 节点已终止
constexpr int Voted = 1;    ///< 本轮已经投过票了
constexpr int Expire = 2;   ///< 投票（消息、竞选者）过期
constexpr int Normal = 3;   ///< 正常状态

/**
 * @class Raft
 * @brief Raft 共识算法核心实现类
 * 
 * 实现了完整的 Raft 共识算法，包括：
 * - 领导者选举（Leader Election）
 * - 日志复制（Log Replication）
 * - 安全性保证（Safety）
 * - 快照机制（Snapshot）
 * 
 * 主要特性：
 * - 强一致性保证
 * - 分区容错性
 * - 自动故障恢复
 * - 日志压缩优化
 */
class Raft : public raftRpcProctoc::raftRpc {
 private:
  // ========== 基础状态 ==========
  std::mutex m_mtx;                                        ///< 互斥锁，保证线程安全
  std::vector<std::shared_ptr<RaftRpcUtil>> m_peers;      ///< 与其他 Raft 节点通信的 RPC 入口
  std::shared_ptr<Persister> m_persister;                 ///< 持久化层，负责 Raft 数据的持久化
  int m_me;                                                ///< 当前节点的编号标识
  
  // ========== 持久化状态（所有服务器） ==========
  int m_currentTerm;                                       ///< 当前任期号
  int m_votedFor;                                          ///< 当前任期投票给了哪个候选者
  std::vector<raftRpcProctoc::LogEntry> m_logs;           ///< 日志条目数组，包含状态机指令和任期号
  
  // ========== 易失状态（所有服务器） ==========
  int m_commitIndex;                                       ///< 已提交的最高日志索引
  int m_lastApplied;                                       ///< 已应用到状态机的最高日志索引
  
  // ========== 易失状态（仅 Leader） ==========
  std::vector<int> m_nextIndex;                           ///< 发送给每个服务器的下一个日志索引
  std::vector<int> m_matchIndex;                          ///< 每个服务器已复制的最高日志索引
  
  // ========== 节点角色 ==========
  enum Status { Follower, Candidate, Leader };            ///< 节点状态枚举
  Status m_status;                                         ///< 当前节点状态
  
  // ========== 通信接口 ==========
  std::shared_ptr<LockQueue<ApplyMsg>> applyChan;         ///< 与上层应用通信的消息队列
  
  // ========== 定时器相关 ==========
  std::chrono::_V2::system_clock::time_point m_lastResetElectionTime;  ///< 上次重置选举定时器的时间
  std::chrono::_V2::system_clock::time_point m_lastResetHearBeatTime;   ///< 上次重置心跳定时器的时间
  
  // ========== 快照相关 ==========
  int m_lastSnapshotIncludeIndex;                         ///< 快照包含的最后一个日志索引
  int m_lastSnapshotIncludeTerm;                          ///< 快照包含的最后一个日志任期
  
  // ========== 协程管理 ==========
  std::unique_ptr<monsoon::IOManager> m_ioManager = nullptr;  ///< IO 管理器，用于协程调度

 public:
  // ========== 核心 RPC 接口 ==========
  /**
   * @brief 日志追加 RPC 处理函数
   * @param args 请求参数
   * @param reply 响应结果
   * 
   * 处理来自 Leader 的日志同步和心跳请求
   * 这是 Raft 算法的核心函数之一
   */
  void AppendEntries1(const raftRpcProctoc::AppendEntriesArgs *args, raftRpcProctoc::AppendEntriesReply *reply);
  
  /**
   * @brief 定期向状态机应用日志
   * 将已提交但未应用的日志条目发送给上层状态机
   */
  void applierTicker();
  
  /**
   * @brief 条件安装快照
   * @param lastIncludedTerm 快照包含的最后日志任期
   * @param lastIncludedIndex 快照包含的最后日志索引
   * @param snapshot 快照数据
   * @return 是否成功安装快照
   */
  bool CondInstallSnapshot(int lastIncludedTerm, int lastIncludedIndex, std::string snapshot);
  
  /**
   * @brief 发起领导者选举
   * 当节点成为候选者时，向其他节点发送投票请求
   */
  void doElection();
  
  /**
   * @brief 发起心跳
   * 只有 Leader 才需要发起心跳，用于维持权威和同步日志
   */
  void doHeartBeat();
  
  /**
   * @brief 选举超时检查器
   * 定期检查是否需要发起选举
   * 如果在超时时间内没有收到 Leader 的心跳，则发起选举
   */
  void electionTimeOutTicker();
  
  // ========== 日志管理 ==========
  /**
   * @brief 获取待应用的日志条目
   * @return 待应用的日志消息列表
   */
  std::vector<ApplyMsg> getApplyLogs();
  
  /**
   * @brief 获取新命令的日志索引
   * @return 新命令应该插入的日志索引
   */
  int getNewCommandIndex();
  
  /**
   * @brief 获取指定服务器的前一个日志信息
   * @param server 目标服务器 ID
   * @param preIndex 输出参数：前一个日志索引
   * @param preTerm 输出参数：前一个日志任期
   */
  void getPrevLogInfo(int server, int *preIndex, int *preTerm);
  
  /**
   * @brief 获取当前节点状态
   * @param term 输出参数：当前任期
   * @param isLeader 输出参数：是否为 Leader
   */
  void GetState(int *term, bool *isLeader);
  
  // ========== 快照相关 ==========
  /**
   * @brief 安装快照 RPC 处理函数
   * @param args 快照请求参数
   * @param reply 快照响应结果
   */
  void InstallSnapshot(const raftRpcProctoc::InstallSnapshotRequest *args,
                       raftRpcProctoc::InstallSnapshotResponse *reply);
  
  /**
   * @brief Leader 心跳定时器
   * 检查是否需要发起心跳（仅 Leader 使用）
   */
  void leaderHearBeatTicker();
  
  /**
   * @brief Leader 发送快照给指定服务器
   * @param server 目标服务器 ID
   */
  void leaderSendSnapShot(int server);
  
  /**
   * @brief Leader 更新提交索引
   * 根据大多数节点的匹配情况更新 commitIndex
   */
  void leaderUpdateCommitIndex();
  
  // ========== 辅助函数 ==========
  /**
   * @brief 检查日志是否匹配
   * @param logIndex 日志索引
   * @param logTerm 日志任期
   * @return 是否匹配
   */
  bool matchLog(int logIndex, int logTerm);
  
  /**
   * @brief 持久化当前状态
   * 将关键状态保存到持久化存储中
   */
  void persist();
  
  /**
   * @brief 投票请求 RPC 处理函数
   * @param args 投票请求参数
   * @param reply 投票响应结果
   */
  void RequestVote(const raftRpcProctoc::RequestVoteArgs *args, raftRpcProctoc::RequestVoteReply *reply);
  
  /**
   * @brief 判断候选者日志是否足够新
   * @param index 候选者最后日志索引
   * @param term 候选者最后日志任期
   * @return 是否足够新
   */
  bool UpToDate(int index, int term);
  
  // ========== 日志信息获取 ==========
  /**
   * @brief 获取最后一个日志的索引
   * @return 最后日志索引
   */
  int getLastLogIndex();
  
  /**
   * @brief 获取最后一个日志的任期
   * @return 最后日志任期
   */
  int getLastLogTerm();
  
  /**
   * @brief 获取最后一个日志的索引和任期
   * @param lastLogIndex 输出参数：最后日志索引
   * @param lastLogTerm 输出参数：最后日志任期
   */
  void getLastLogIndexAndTerm(int *lastLogIndex, int *lastLogTerm);
  
  /**
   * @brief 根据日志索引获取日志任期
   * @param logIndex 日志索引
   * @return 对应的日志任期
   */
  int getLogTermFromLogIndex(int logIndex);
  
  /**
   * @brief 获取 Raft 状态大小
   * @return 状态数据的字节数
   */
  int GetRaftStateSize();
  
  /**
   * @brief 根据日志索引获取在数组中的位置
   * @param logIndex 逻辑日志索引
   * @return 在日志数组中的实际位置
   * 
   * 引入快照后，logIndex 不能直接作为数组下标使用
   */
  int getSlicesIndexFromLogIndex(int logIndex);
  
  // ========== RPC 发送函数 ==========
  /**
   * @brief 向指定服务器发送投票请求
   * @param server 目标服务器 ID
   * @param args 投票请求参数
   * @param reply 投票响应结果
   * @param votedNum 已获得的票数
   * @return 是否发送成功
   */
  bool sendRequestVote(int server, std::shared_ptr<raftRpcProctoc::RequestVoteArgs> args,
                       std::shared_ptr<raftRpcProctoc::RequestVoteReply> reply, std::shared_ptr<int> votedNum);
  
  /**
   * @brief 向指定服务器发送日志追加请求
   * @param server 目标服务器 ID
   * @param args 日志追加请求参数
   * @param reply 日志追加响应结果
   * @param appendNums 成功追加的数量
   * @return 是否发送成功
   */
  bool sendAppendEntries(int server, std::shared_ptr<raftRpcProctoc::AppendEntriesArgs> args,
                         std::shared_ptr<raftRpcProctoc::AppendEntriesReply> reply, std::shared_ptr<int> appendNums);
  
  // ========== 消息处理 ==========
  /**
   * @brief 向上层服务推送消息
   * @param msg 应用消息
   * 
   * 将消息发送到 applyChan，不持锁执行
   */
  void pushMsgToKvServer(ApplyMsg msg);
  
  // ========== 持久化相关 ==========
  /**
   * @brief 从持久化数据中恢复状态
   * @param data 持久化的数据
   */
  void readPersist(std::string data);
  
  /**
   * @brief 序列化当前状态
   * @return 序列化后的数据
   */
  std::string persistData();
  
  // ========== 客户端接口 ==========
  /**
   * @brief 启动新的命令
   * @param command 要执行的命令
   * @param newLogIndex 输出参数：新日志索引
   * @param newLogTerm 输出参数：新日志任期
   * @param isLeader 输出参数：当前是否为 Leader
   */
  void Start(Op command, int *newLogIndex, int *newLogTerm, bool *isLeader);
  
  /**
   * @brief 创建快照
   * @param index 快照包含的最后日志索引
   * @param snapshot 快照数据
   * 
   * 服务层主动请求 Raft 保存快照数据，用于日志压缩
   */
  void Snapshot(int index, std::string snapshot);

 public:
  // ========== gRPC 接口实现 ==========
  /**
   * @brief 日志追加 gRPC 接口
   * @param controller RPC 控制器
   * @param request 请求参数
   * @param response 响应结果
   * @param done 完成回调
   */
  void AppendEntries(google::protobuf::RpcController *controller, const ::raftRpcProctoc::AppendEntriesArgs *request,
                     ::raftRpcProctoc::AppendEntriesReply *response, ::google::protobuf::Closure *done) override;
  
  /**
   * @brief 安装快照 gRPC 接口
   * @param controller RPC 控制器
   * @param request 请求参数
   * @param response 响应结果
   * @param done 完成回调
   */
  void InstallSnapshot(google::protobuf::RpcController *controller,
                       const ::raftRpcProctoc::InstallSnapshotRequest *request,
                       ::raftRpcProctoc::InstallSnapshotResponse *response, ::google::protobuf::Closure *done) override;
  
  /**
   * @brief 投票请求 gRPC 接口
   * @param controller RPC 控制器
   * @param request 请求参数
   * @param response 响应结果
   * @param done 完成回调
   */
  void RequestVote(google::protobuf::RpcController *controller, const ::raftRpcProctoc::RequestVoteArgs *request,
                   ::raftRpcProctoc::RequestVoteReply *response, ::google::protobuf::Closure *done) override;

 public:
  /**
   * @brief 初始化 Raft 节点
   * @param peers 其他节点的 RPC 连接
   * @param me 当前节点 ID
   * @param persister 持久化器
   * @param applyCh 应用消息通道
   */
  void init(std::vector<std::shared_ptr<RaftRpcUtil>> peers, int me, std::shared_ptr<Persister> persister,
            std::shared_ptr<LockQueue<ApplyMsg>> applyCh);

 private:
  // ========== 持久化辅助类 ==========
  /**
   * @class BoostPersistRaftNode
   * @brief 用于 Boost 序列化的 Raft 节点状态
   * 
   * 封装需要持久化的关键状态，支持序列化和反序列化
   */
  class BoostPersistRaftNode {
   public:
    friend class boost::serialization::access;
    
    /**
     * @brief 序列化函数
     * @param ar 归档对象
     * @param version 版本号
     * 
     * 当 Archive 对应输出归档时，& 操作符类似于 <<
     * 当 Archive 对应输入归档时，& 操作符类似于 >>
     */
    template <class Archive>
    void serialize(Archive &ar, const unsigned int version) {
      ar &m_currentTerm;              // 当前任期
      ar &m_votedFor;                 // 投票对象
      ar &m_lastSnapshotIncludeIndex; // 快照最后索引
      ar &m_lastSnapshotIncludeTerm;  // 快照最后任期
      ar &m_logs;                     // 日志条目
    }
    
    int m_currentTerm;                          ///< 当前任期号
    int m_votedFor;                             ///< 当前任期投票给了谁
    int m_lastSnapshotIncludeIndex;             ///< 快照包含的最后日志索引
    int m_lastSnapshotIncludeTerm;              ///< 快照包含的最后日志任期
    std::vector<std::string> m_logs;            ///< 序列化后的日志条目
    std::unordered_map<std::string, int> umap;  ///< 辅助映射表
  };
};

#endif  // RAFT_H